#pragma once
#include "hBitStr.h"

namespace _hHuffmanDetail
{
	struct Node
	{
		size_t _freq = 0;
		Node* _left = NULL;
		Node* _right = NULL;

		virtual ~Node() {}
		virtual uint8_t getKey() const { return 0; }
		virtual uint16_t getCode() const { return 0; }
		virtual std::ostream& fillOs(std::ostream& os) const;
		size_t calcHeight() const;
		const Node* getNodeByHeight(size_t height, size_t idx) const;

	};

	struct CharNode : public Node
	{
		uint8_t _key = 0;

		uint8_t getKey() const { return _key; }
		uint16_t getCode() const { return 0x100 | _key; }
		std::ostream& fillOs(std::ostream& os) const;
	};

	union Bit8
	{
		int8_t _val = 0;
		uint8_t _uval;

		bool operator[](uint8_t b) const;
		std::ostream& fillOs(std::ostream& os) const;
	};

	struct CodeParam
	{
		hBitStr& _outBit;
		const char* _inDt = NULL;
		size_t _len = 0;
		Node* _pTree = NULL;
		std::map<uint8_t, size_t> _charTab;
		std::map<uint8_t, hBitStr> _keyTab;
		std::multimap<size_t, Node*> _freqTab;

		void init();
		void show();
		void fin();
		void code();
		void showCharTab() const;
		void showKeyTab() const;
		void showTree() const;
		void showBit() const;

		void genKeyTabCb(const Node* pTree, hBitStr val);
		void codeTreeCb(const Node* pTree);
		void finCb(const Node* pTree);
	};

	struct DecodeParam
	{
		const hBitStr& _inBit;
		hBitStrView _view{ _inBit };
		size_t _len = 0;
		Node* _pTree = NULL;

		void init();
		void show();
		void fin();
		template <typename T>
		void decode(T& outDt) {}
		template <>
		void decode<std::string>(std::string& outDt);
		void showCharTab() const;
		void showKeyTab() const;
		void showTree() const;
		void showBit() const;

		void genTreeCb(Node*& pTree);
		void codeTreeCb(const Node* pTree);
		void finCb(const Node* pTree);
	};
}
